home *** CD-ROM | disk | FTP | other *** search
Korn shell script | 1997-08-26 | 9.7 KB | 382 lines |
- #!/bin/ksh
- # @(#) msgs.ksh 1.1 97/06/09
- # 91/09/23 john h. dubois iii (john@armory.com)
- # 91/10/12 added interactive option to go to a particular message
- # 91/11/03 added -n option
- # 92/01/30 added header commands, keep track of firstmsg,
- # assorted other improvements
- # 92/01/31 fixed IFS prob by making it local to pager()
- # added $ to header range options
- # 92/03/02 added test for readability of range file.
- # 92/03/10 added save-message feature
- # 92/07/08 added / to message options
- # 92/09/20 Skip up to From: line
- # 92/09/26 Added -e to egrep line
- # 93/02/02 Check what messages actually exist when -q is given
- # 93/02/04 Allow ranges for most commands
- # 93/02/22 Fixed n to actually skip messages
- # 93/04/01 Added $ command line option
- # 93/04/08 Make / search files in numerical order
- # 93/09/16 Added -s
- # 93/09/21 Added -w & -n
- # 93/12/28 Added -i to egrep args.
- # Eliminated trailing space added to search args.
- # 94/05/13 Be annoying if there are old unread messages.
- # 97/06/09 Deal with bad .msgsrc file gracefully.
-
- # This utility operates on a collection of message files in a publicly
- # accessible directory named /usr/spool/msgs. The message files should be
- # in RFC822 format, with at least a From: and Subject: line in the header.
- # The filenames should be positive integer numbers.
- # In the /usr/spool/msgs directory, there should also be a file named "range".
- # The range file should contain two numbers separated by whitespace, with the
- # numbers being the first and last message numbers.
-
- alias istrue="test 0 -ne"
- alias isfalse="test 0 -eq"
-
- typeset -i firstmsg lastmsg unread=0 highestread neverread lines lastmsgread=0
- typeset -i debug=0
-
- rcfile=$HOME/.msgsrc
- msgdir=/usr/spool/msgs
- name=${0##*/}
-
- function waitexit {
- if istrue wait; then
- print -n "Press <return> to exit msgs..."
- read
- fi
- exit 0
- }
-
- # Usage: pager [filename]
- # If no filename is given, pager pages stdin.
- # If a filename is given, it is taken to be a message and the header lines
- # up to, but not including, the From: line are skipped, if possible.
- # If the input is <= $lines lines long, it will paged by $PAGER.
- # Otherwise, it will be printed directly.
- function pager {
- typeset input msg
- typeset -i count=0 infile=$1 FromLine=0
- typeset IFS= # Avoid losing leading & trailing space on read
- if [ $# -eq 0 ]; then
- while [ count -le lines ] && read input; do
- msg="$msg
- $input"
- let count+=1
- done
- if [ count -gt lines ]; then
- (
- print -r "$msg"
- while read input; do
- print -r "$input"
- done ) | $PAGER
- else
- print -r "$msg"
- fi
- else
- while [ count -le lines ] && read input; do
- if isfalse count; then
- let FromLine+=1
- if [[ "$input" = From:* ]]; then
- msg="$msg
- $input"
- count=1
- fi
- else
- let count+=1
- msg="$msg
- $input"
- fi
- done < "$infile"
- if [ count -gt lines ]; then
- if [[ $PAGER = *?(more|less|pg) ]]; then
- $PAGER +$FromLine "$infile"
- else
- $PAGER "$infile"
- fi
- else
- print -r "$msg"
- fi
- fi
- }
-
- # Usage: headers first-last
- # Prints the headers for messages
- function headers {
- typeset -i range1 range2
- typeset msglist range=$1
-
- cd $msgdir
- range1=${range%-*}
- range2=${range#*-}
- while [ range1 -le range2 ]; do
- [ -f $range1 ] && msglist="$msglist $range1"
- let range1+=1
- done
- if [ -z "$msglist" ]; then
- echo "$name: No messages."
- else
- # Include /dev/null so that there will always be at least
- # two files (if there are any at all) so that filenames
- # (message numbers) will be prepended to Subject lines
- egrep '^Subject: ' /dev/null $msglist | sed s/:Subject:// | pager
- fi
- }
-
- function chknums {
- if [ $# -eq 0 -o $# -eq 1 -a "$1" -gt lastmsg ]; then
- print -u2 "$name: No message numbers given."
- return 1
- else
- return 0
- fi
- }
-
- # Usage: action cmd args ranges
- function action {
- typeset cmd=$1 args=$2 message msglist
- ret=0
- shift 2
-
- case $cmd in
- d) chknums "$@" && rm $* && echo "Removed $*.";;
- n) ;;
- s) msglist=$*
- chknums "$@" || return 1
- set -- $args
- case $# in
- 0) echo "$name: No filename given."
- return 1;;
- 1)
- cd $OPWD
- [ -f "$1" ] && act=appended || act=written
- (cd $msgdir; cat $msglist) >> $1 &&
- echo "Message(s) $msglist $act to file \"$1\"" ||
- ret=1
- cd $msgdir
- return $ret;;
- *) echo "$name: Too many arguments."
- return 1;
- esac;;
- x) exit;;
- y) chknums "$@" &&
- for message; do
- pager $message
- done;;
- \?) echo \
- "y or <cr>: yes, read the message
- n: no, skip the message
- q: quit
- s <filename>: save the message to file <filename>
- x: exit without updating .msgsrc file
- h: print headers
- /<pattern>: find lines in messages that match <pattern>
- ?: print this help
- nnn: read message number nnn"
- ;;
- h) chknums "$@" &&
- egrep '^Subject: ' /dev/null $* | sed s/:Subject:// | pager
- ;;
- /*) if [ "$cmd" != / ]; then
- [ -n "$args" ] && args="${cmd#/} $args" || args="${cmd#/}"
- fi
- shift
- chknums "$@" || return 1
- if [ $# -eq 0 ]; then
- typeset -i pos=1
- typeset pat=
- set -A Files
- while [ pos -le 5 ]; do
- pat="$pat[0-9]"
- set -- $pat
- [ -r "$1" ] && set -A Files ${Files[*]} $*
- let pos+=1
- done
- set -- ${Files[*]}
- fi
- egrep -i "$args" /dev/null $* | pager
- ;;
- *) echo "$name: Invalid command.";
- return 1;;
- esac
- }
-
- [ -f $rcfile -a ! -r $rcfile ] && exit
- if [ ! -r $msgdir/range ]; then
- print -u2 "$name: Cannot open range file."
- exit
- fi
-
- read firstmsg lastmsg < $msgdir/range
-
- if [ -f $rcfile ]; then
- read lastmsgread < $rcfile || {
- print "Bad last-message-read in your $rcfile file; removing it..."
- rm -f -- $rcfile
- neverread=1
- }
- else
- neverread=1
- fi 2>/dev/null
-
- [ firstmsg -gt lastmsgread ] && lastmsgread=firstmsg-1
-
- highestread=lastmsgread
- typeset -i wait=0 noquit=0 MsgAge
-
- OPWD=$PWD
- cd $msgdir
-
- for arg; do
- case "$arg" in
- -q)
- typeset -i curmsg=$lastmsgread+1
- # Count unread messages
- let lastmsgread+=1
- while [ lastmsgread -le lastmsg ]; do
- [ -f $msgdir/$lastmsgread ] && let unread+=1
- let lastmsgread+=1
- done
- case $unread in
- 0) ;;
- 1) echo "There is one new system message.";;
- *) echo "There are $unread new system messages.";;
- esac
- if istrue neverread || [ unread -gt 2 ]; then
- # Be annoying if there are old unread messages.
- if type stat unixtime > /dev/null; then
- # Find oldest unread message
- istrue debug && set -x
- istrue debug && print $curmsg $lastmsg
- while [ curmsg -le lastmsg -a ! -r $curmsg ]; do
- curmsg=curmsg+1
- done
- if [ curmsg -le lastmsg ]; then
- MsgAge="($(unixtime)-$(stat -nfm $curmsg))/86400"
- [ $MsgAge -gt 60 ] &&
- print "\007\007\007It is important to read them."
- fi
- fi
- echo 'Type "msgs" to read the system messages.'
- fi
- exit $unread;;
- +([0-9]))
- lastmsgread=$1-1;;
- -+([0-9]))
- lastmsgread=lastmsg$1;;
- $)
- lastmsgread=lastmsg-1;;
- -s)
- [ lastmsgread -lt lastmsg ] && headers $((lastmsgread+1))-$lastmsg
- waitexit;;
- -h)
- echo \
- "$name: read system messages.
- Usage: $name [-wqnhs] [[-]<num>]
- If a number is given as an argument, msgs will take it to be the first
- message to read. If the number has a '-' in front of it, msgs will make the
- first message to read be the last system message minus the number given.
- Options:
- -q: Print a message if there are unread system messages.
- Otherwise exit without printing anything.
- The exit value is equal to the number of unread system messages.
- -s: Print the subjects of the messages that would be read.
- -h: Print this help.
- -n: Do not quit after printing the last message.
- This can be used to read messages even if all messages have been read.
- -w: Wait after printing the last message until return is pressed,
- for use with a windowing environment."
- waitexit;;
- -w)
- wait=1;;
- -x)
- debug=1;;
- -n)
- noquit=1;;
- *)
- echo "$name: $arg: Invalid argument. Use -h for help."
- exit 1
- ;;
- esac
- done
-
- [ -z "$PAGER" ] && PAGER=less
-
- if [ lastmsgread -ge lastmsg ]; then
- echo "No new messages."
- isfalse noquit && waitexit
- fi
-
- lines=$(tput lines)-4
-
- typeset -i curmsg=$lastmsgread+1 range1 range2
-
- function isrange {
- [[ "$1" = @(+([0-9])|-+([0-9])|+([0-9])-+([0-9])|+([0-9])-|+([0-9])-\$|\$) ]]
- }
-
- while [ curmsg -le lastmsg ] || istrue noquit; do
- if [ ! -r $curmsg -a curmsg -le lastmsg ]; then
- curmsg=curmsg+1
- continue
- fi
- if [ curmsg -le lastmsg ]; then
- subject=$(egrep '^Subject: ' $curmsg)
- echo -n "\nMessage #$curmsg\n$subject\nRead [ynqsxh/?]? "
- else
- echo -n "\n[qsxh/?]? "
- fi
- read line
- # response format: [cmd] [range ...] [filename]
- [ -z "$line" ] && line=y
- set -- $line
- if isrange $1; then
- cmd=y
- else
- cmd=$1
- shift
- fi
- [ "$cmd" = q ] && break
- if [ "$cmd" = h -a $# = 0 ]; then
- [ curmsg -gt lastmsg ] && set -- 1- || set -- $curmsg-
- fi
- msglist= range=
- while isrange $1; do
- range=$1
- case $range in
- +([0-9])) range1=$range range2=$range;;
- +([0-9])-+([0-9])) range1=${range%-*} range2=${range#*-};;
- -+([0-9])) range1=curmsg$range range2=lastmsg;;
- +([0-9])-) range1=${range%-} range2=lastmsg;;
- +([0-9])-\$) range1=${range%-*} range2=lastmsg;;
- \$) range1=lastmsg range2=lastmsg;;
- *) echo "Invalid range: $range."; continue;;
- esac
- rangemsgs=
- while [ range1 -le range2 ]; do
- [ -r $range1 ] && rangemsgs="$rangemsgs $range1"
- let range1+=1
- done
- if [ -z "$rangemsgs" ]; then
- echo "No messages in range '$1'."
- else
- msglist="$msglist $rangemsgs"
- fi
- shift
- done
- [ -z "$range" ] && msglist=$curmsg
- [ -z "$msglist" ] && continue
- action "$cmd" "$*" $msglist
- [[ curmsg -gt highestread ]] && highestread=curmsg
- if [[ $cmd = [ny] ]]; then
- set -- $msglist
- shift $(($#-1))
- curmsg=$1+1
- fi
- done
- [ $highestread -gt lastmsg ] && highestread=$lastmsg
- echo $highestread > $rcfile
- waitexit
-